/*
 * @Descripttion: call bind apply的实现
 * @version: 1.0.0
 * @Author: 某人
 * @Date: 2021-05-26 14:41:49
 */
// call使用一个指定的 this 值和一个或多个参数来调用一个函数
Function.prototype.call2 = function (context) {
  var context = context || window
  context.fn = this
  var args = []
  for (var i = 1, len = arguments.length; i < len; i++) {
    args.push(`arguments['${i}]`)
  }
  var result = eval(`context.fn(${args})`)
  delete context.fn
  return result
}

// apply
Function.prototype.apply2 = function (context, arr) {
  var context = context || window
  context.fn = this
  var result;
  if (!arr) {
    result = context.fn()
  } else {
    var args = []
    for (let i = 0, len = arguments.length; i < len; i++) {
      args.push(`arr[${i}]`)
    }
    result = eval(`context.fn(${args})`)
  }
  delete context.fn
  return result
}

// bind
// 方法会创建一个新的函数，在 bind() 被调用时，这个新函数的 this 被指定为 bind() 的第一个参数，而其余参数将作为新函数的参数，供调用时使用。
Function.prototype.bind2 = function (context) {
  // var context = context || window
  var self = this
  var args = Array.prototype.slice.call(arguments, 1)
  var fNOP = function () {}
  var fBound = function () {
    var bindArgs = Array.prototype.slice.call(arguments)
    return self.apply(this instanceof fNOP ? this : context, args.concat(bindArgs))
  }
  fNOP.prototype = this.prototype
  fBound.prototype = new fNOP()
  return fBound
}